package com.sky.orangehireserver.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;

/**
 * 加密工具类
 * 提供常用的加密、解密、哈希等功能
 *
 * @author sky
 */
@Slf4j
public class EncryptUtil {

    private static final String AES_ALGORITHM = "AES";
    private static final String AES_TRANSFORMATION = "AES/CBC/PKCS5Padding";
    private static final String HMAC_SHA256_ALGORITHM = "HmacSHA256";
    private static final String MD5_ALGORITHM = "MD5";
    private static final String SHA1_ALGORITHM = "SHA-1";
    private static final String SHA256_ALGORITHM = "SHA-256";
    private static final String SHA512_ALGORITHM = "SHA-512";

    /**
     * MD5 加密
     *
     * @param input 待加密字符串
     * @return MD5 加密后的字符串（32位小写）
     */
    public static String md5(String input) {
        if (StringUtils.isBlank(input)) {
            return null;
        }
        try {
            MessageDigest md = MessageDigest.getInstance(MD5_ALGORITHM);
            byte[] digest = md.digest(input.getBytes(StandardCharsets.UTF_8));
            return bytesToHex(digest);
        } catch (NoSuchAlgorithmException e) {
            log.error("MD5 encryption failed", e);
            throw new RuntimeException("MD5 encryption failed", e);
        }
    }

    /**
     * SHA-1 加密
     *
     * @param input 待加密字符串
     * @return SHA-1 加密后的字符串
     */
    public static String sha1(String input) {
        if (StringUtils.isBlank(input)) {
            return null;
        }
        try {
            MessageDigest md = MessageDigest.getInstance(SHA1_ALGORITHM);
            byte[] digest = md.digest(input.getBytes(StandardCharsets.UTF_8));
            return bytesToHex(digest);
        } catch (NoSuchAlgorithmException e) {
            log.error("SHA-1 encryption failed", e);
            throw new RuntimeException("SHA-1 encryption failed", e);
        }
    }

    /**
     * SHA-256 加密
     *
     * @param input 待加密字符串
     * @return SHA-256 加密后的字符串
     */
    public static String sha256(String input) {
        if (StringUtils.isBlank(input)) {
            return null;
        }
        try {
            MessageDigest md = MessageDigest.getInstance(SHA256_ALGORITHM);
            byte[] digest = md.digest(input.getBytes(StandardCharsets.UTF_8));
            return bytesToHex(digest);
        } catch (NoSuchAlgorithmException e) {
            log.error("SHA-256 encryption failed", e);
            throw new RuntimeException("SHA-256 encryption failed", e);
        }
    }

    /**
     * SHA-512 加密
     *
     * @param input 待加密字符串
     * @return SHA-512 加密后的字符串
     */
    public static String sha512(String input) {
        if (StringUtils.isBlank(input)) {
            return null;
        }
        try {
            MessageDigest md = MessageDigest.getInstance(SHA512_ALGORITHM);
            byte[] digest = md.digest(input.getBytes(StandardCharsets.UTF_8));
            return bytesToHex(digest);
        } catch (NoSuchAlgorithmException e) {
            log.error("SHA-512 encryption failed", e);
            throw new RuntimeException("SHA-512 encryption failed", e);
        }
    }

    /**
     * HMAC-SHA256 加密
     *
     * @param data 待加密数据
     * @param key  密钥
     * @return HMAC-SHA256 加密后的字符串
     */
    public static String hmacSha256(String data, String key) {
        if (StringUtils.isBlank(data) || StringUtils.isBlank(key)) {
            return null;
        }
        try {
            Mac mac = Mac.getInstance(HMAC_SHA256_ALGORITHM);
            SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), HMAC_SHA256_ALGORITHM);
            mac.init(secretKeySpec);
            byte[] digest = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
            return bytesToHex(digest);
        } catch (Exception e) {
            log.error("HMAC-SHA256 encryption failed", e);
            throw new RuntimeException("HMAC-SHA256 encryption failed", e);
        }
    }

    /**
     * 生成 AES 密钥
     *
     * @return Base64 编码的 AES 密钥
     */
    public static String generateAESKey() {
        try {
            KeyGenerator keyGenerator = KeyGenerator.getInstance(AES_ALGORITHM);
            keyGenerator.init(256); // 256位密钥
            SecretKey secretKey = keyGenerator.generateKey();
            return Base64.getEncoder().encodeToString(secretKey.getEncoded());
        } catch (NoSuchAlgorithmException e) {
            log.error("Generate AES key failed", e);
            throw new RuntimeException("Generate AES key failed", e);
        }
    }

    /**
     * AES 加密
     *
     * @param plainText 明文
     * @param key       Base64 编码的密钥
     * @return Base64 编码的密文（包含 IV）
     */
    public static String aesEncrypt(String plainText, String key) {
        if (StringUtils.isBlank(plainText) || StringUtils.isBlank(key)) {
            return null;
        }
        try {
            byte[] keyBytes = Base64.getDecoder().decode(key);
            SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, AES_ALGORITHM);

            Cipher cipher = Cipher.getInstance(AES_TRANSFORMATION);
            
            // 生成随机 IV
            byte[] iv = new byte[16];
            new SecureRandom().nextBytes(iv);
            IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
            
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
            byte[] encrypted = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
            
            // 将 IV 和密文合并
            byte[] encryptedWithIv = new byte[iv.length + encrypted.length];
            System.arraycopy(iv, 0, encryptedWithIv, 0, iv.length);
            System.arraycopy(encrypted, 0, encryptedWithIv, iv.length, encrypted.length);
            
            return Base64.getEncoder().encodeToString(encryptedWithIv);
        } catch (Exception e) {
            log.error("AES encryption failed", e);
            throw new RuntimeException("AES encryption failed", e);
        }
    }

    /**
     * AES 解密
     *
     * @param cipherText Base64 编码的密文（包含 IV）
     * @param key        Base64 编码的密钥
     * @return 明文
     */
    public static String aesDecrypt(String cipherText, String key) {
        if (StringUtils.isBlank(cipherText) || StringUtils.isBlank(key)) {
            return null;
        }
        try {
            byte[] keyBytes = Base64.getDecoder().decode(key);
            SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, AES_ALGORITHM);
            
            byte[] encryptedWithIv = Base64.getDecoder().decode(cipherText);
            
            // 提取 IV
            byte[] iv = new byte[16];
            System.arraycopy(encryptedWithIv, 0, iv, 0, iv.length);
            IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
            
            // 提取密文
            byte[] encrypted = new byte[encryptedWithIv.length - iv.length];
            System.arraycopy(encryptedWithIv, iv.length, encrypted, 0, encrypted.length);
            
            Cipher cipher = Cipher.getInstance(AES_TRANSFORMATION);
            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
            byte[] decrypted = cipher.doFinal(encrypted);
            
            return new String(decrypted, StandardCharsets.UTF_8);
        } catch (Exception e) {
            log.error("AES decryption failed", e);
            throw new RuntimeException("AES decryption failed", e);
        }
    }

    /**
     * Base64 编码
     *
     * @param input 待编码字符串
     * @return Base64 编码后的字符串
     */
    public static String base64Encode(String input) {
        if (StringUtils.isBlank(input)) {
            return null;
        }
        return Base64.getEncoder().encodeToString(input.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * Base64 解码
     *
     * @param input Base64 编码的字符串
     * @return 解码后的字符串
     */
    public static String base64Decode(String input) {
        if (StringUtils.isBlank(input)) {
            return null;
        }
        try {
            byte[] decoded = Base64.getDecoder().decode(input);
            return new String(decoded, StandardCharsets.UTF_8);
        } catch (Exception e) {
            log.error("Base64 decode failed", e);
            throw new RuntimeException("Base64 decode failed", e);
        }
    }

    /**
     * 生成随机盐值
     *
     * @param length 盐值长度
     * @return Base64 编码的随机盐值
     */
    public static String generateSalt(int length) {
        byte[] salt = new byte[length];
        new SecureRandom().nextBytes(salt);
        return Base64.getEncoder().encodeToString(salt);
    }

    /**
     * 密码加盐哈希（推荐用于密码存储）
     *
     * @param password 原始密码
     * @param salt     盐值
     * @return SHA-256 加盐哈希后的密码
     */
    public static String hashPassword(String password, String salt) {
        if (StringUtils.isBlank(password) || StringUtils.isBlank(salt)) {
            return null;
        }
        return sha256(password + salt);
    }

    /**
     * 验证密码
     *
     * @param password     原始密码
     * @param salt         盐值
     * @param hashedPassword 存储的哈希密码
     * @return 密码是否匹配
     */
    public static boolean verifyPassword(String password, String salt, String hashedPassword) {
        if (StringUtils.isAnyBlank(password, salt, hashedPassword)) {
            return false;
        }
        String computedHash = hashPassword(password, salt);
        return hashedPassword.equals(computedHash);
    }

    /**
     * 字节数组转十六进制字符串
     *
     * @param bytes 字节数组
     * @return 十六进制字符串（小写）
     */
    private static String bytesToHex(byte[] bytes) {
        StringBuilder result = new StringBuilder();
        for (byte b : bytes) {
            result.append(String.format("%02x", b));
        }
        return result.toString();
    }
}
